#include "utest.h"
#include "hashset.h"

ctl_err_code set_equal(ctl_hashset_int_hash_equal* ht, int* arr, size_t arr_size) {
  int* arr_flag = (int*)malloc(sizeof(int) * arr_size);
  size_t arr_idx = 0U;
  for (arr_idx = 0U; arr_idx < arr_size; arr_idx++) {
   arr_flag[arr_idx] = 0; 
  }
  ctl_res_ctl_hashset_int_hash_equal_iter iter = ctl_hashset_int_hash_equal_begin(ht);
  while (iter.ec != ENOTFOUND) {
    int value = ctl_hashset_int_hash_equal_iter_data(iter.value).value;
    for (arr_idx = 0U; arr_idx < arr_size; arr_idx++) {
      if (arr[arr_idx] == value) {
        if (!(arr_flag[arr_idx] == 0)) {
          free(arr_flag);
          return ENOTFOUND;
        }
        else{
          arr_flag[arr_idx] = 1;
        }
      } 
    }
    iter = ctl_hashset_int_hash_equal_iter_next(iter.value);
  }
  for (arr_idx = 0U; arr_idx < arr_size; arr_idx++) {
    if (arr_flag[arr_idx] == 0) {
      free(arr_flag);
      return ENOTFOUND;
    }
  }
  free(arr_flag);
  return EOK;
}

UTEST(hashtable, put) {
  ctl_hashset_int_hash_equal* ht = ctl_hashset_int_hash_equal_new().value;
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 0U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_get(ht, 10).ec, ENOTFOUND);
  ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, 10).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 1U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_get(ht, 10).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, 20).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 2U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_get(ht, 20).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, 30).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 3U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, 40).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 4U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, 50).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 5U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, 50).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 5U);
  int expected_arr[5] = {10, 20, 30, 40, 50};
  ASSERT_EQ(set_equal(ht, expected_arr, 5), EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_remove(ht, 60).ec, ENOTFOUND);
  ASSERT_EQ(ctl_hashset_int_hash_equal_remove(ht, 50).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 4U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_remove(ht, 30).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 3U);
  ASSERT_EQ(ctl_hashset_int_hash_equal_remove(ht, 10).ec, EOK);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 2U);
  int expected_arr2[2] = {20, 40};
  ASSERT_EQ(set_equal(ht, expected_arr2, 2U), EOK);
  ctl_hashset_int_hash_equal_free(ht);
}

UTEST(hashtable, loop) {
  ctl_hashset_int_hash_equal* ht = ctl_hashset_int_hash_equal_new().value;
  size_t idx = 0U;
  for (idx = 0U; idx < 1000U; idx++) {
    ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, (int)idx).ec, EOK);
    ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), idx + 1U);
  }
  for (idx = 0U; idx < 1000U; idx++) {
    ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, (int)idx).ec, EOK);
    ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 1000U);
  }
  int* expected_arr = (int*)malloc(sizeof(int) * 1000U);
  for (idx = 0U; idx < 1000U; idx++) {
    expected_arr[idx] = (int)idx;
  }
  ASSERT_EQ(set_equal(ht, expected_arr, 1000U), EOK);
  free(expected_arr);
  for (idx = 0U; idx < 500U; idx++) {
    ASSERT_EQ(ctl_hashset_int_hash_equal_remove(ht, (int)idx).ec, EOK);
    ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 1000U - idx - 1U);
  }
  expected_arr = (int*)malloc(sizeof(int) * 500U);
  for (idx = 0U; idx < 500U; idx++) {
    expected_arr[idx] = (int)(idx + 500U);
  }
  ASSERT_EQ(set_equal(ht, expected_arr, 500U), EOK);
  free(expected_arr);
  ctl_hashset_int_hash_equal_free(ht);
}

UTEST(hashtable, iter) {
  ctl_hashset_int_hash_equal* ht = ctl_hashset_int_hash_equal_new().value;
  size_t idx = 0U;
  for (idx = 0U; idx < 10U; idx++) {
    ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, (int)idx).ec, EOK);
  }
  ctl_res_ctl_hashset_int_hash_equal_iter iter = ctl_hashset_int_hash_equal_get(ht, 8);
  for (idx = 0U; idx < 10U; idx++) {
    ASSERT_EQ(ctl_hashset_int_hash_equal_put(ht, (int)(idx + 10U)).ec, EOK);
  }
  ctl_hashset_int_hash_equal_remove_by_iter(ht, iter.value);
  ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 19U);
  for (idx = 0U; idx < 10U; idx++) {
    iter = ctl_hashset_int_hash_equal_get(ht, (int)(idx + 10U));
    ctl_hashset_int_hash_equal_remove_by_iter(ht, iter.value);
    ASSERT_EQ(ctl_hashset_int_hash_equal_size(ht), 19U - idx - 1U);
  }
  ASSERT_EQ(ctl_hashset_int_hash_equal_get(ht, 8).ec, ENOTFOUND);
  ctl_hashset_int_hash_equal_free(ht);
}
UTEST_MAIN()